package com.sz.admin.system.controller;

import com.sz.core.common.entity.ApiResult;
import com.sz.core.common.enums.CommonResponseEnum;
import com.sz.core.util.CRC16Util;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * CRC Calculation Controller
 * Provides API endpoints for CRC-16/MODBUS calculations
 */
@Tag(name = "CRC Calculation", description = "API for CRC-16/MODBUS checksum calculations")
@RestController
@RequestMapping("/crc")
public class CRCController {

    @Operation(summary = "Calculate CRC-16/MODBUS for string", description = "Calculate CRC-16/MODBUS checksum for input string")
    @PostMapping("/calculate")
    public ApiResult<Map<String, Object>> calculateCRC16(@RequestBody Map<String, String> request) {
        String data = request.get("data");
        if (data == null || data.isEmpty()) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Input data is required"));
        }

        byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
        int crc = CRC16Util.calculateCRC16(bytes);
        String hexCrc = CRC16Util.toHexString(crc);

        Map<String, Object> result = new HashMap<>();
        result.put("input", data);
        result.put("crc", crc);
        result.put("hex", hexCrc);
        result.put("bytes", bytes.length);

        return ApiResult.success(result);
    }

    @Operation(summary = "Calculate CRC-16/MODBUS for hex string", description = "Calculate CRC-16/MODBUS checksum for hex string input")
    @PostMapping("/calculate-hex")
    public ApiResult<Map<String, Object>> calculateCRC16FromHex(@RequestBody Map<String, String> request) {
        String hexData = request.get("hexData");
        if (hexData == null || hexData.isEmpty()) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Hex data is required"));
        }

        try {
            // Convert hex string to byte array
            byte[] bytes = hexStringToByteArray(hexData);
            int crc = CRC16Util.calculateCRC16(bytes);
            String hexCrc = CRC16Util.toHexString(crc);

            Map<String, Object> result = new HashMap<>();
            result.put("input", hexData);
            result.put("crc", crc);
            result.put("hex", hexCrc);
            result.put("bytes", bytes.length);

            return ApiResult.success(result);
        } catch (Exception e) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Invalid hex string format: " + e.getMessage()));
        }
    }

    @Operation(summary = "Calculate CRC-16/MODBUS for decimal number", description = "Convert decimal to hex and calculate CRC-16/MODBUS checksum")
    @PostMapping("/calculate-decimal")
    public ApiResult<Map<String, Object>> calculateCRC16FromDecimal(@RequestBody Map<String, Long> request) {
        Long decimalData = request.get("decimal");
        if (decimalData == null) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Decimal data is required"));
        }

        try {
            // Convert decimal to hex string
            String hexData = Long.toHexString(decimalData).toUpperCase();
            
            // Ensure even number of characters by padding with leading zero if needed
            if (hexData.length() % 2 != 0) {
                hexData = "0" + hexData;
            }
            
            // Pad to 4 characters (2 bytes) with leading zeros if needed
            while (hexData.length() < 4) {
                hexData = "00" + hexData;
            }
            
            // Convert hex string to byte array
            byte[] bytes = hexStringToByteArray(hexData);
            int crc = CRC16Util.calculateCRC16(bytes);
            String hexCrc = CRC16Util.toHexString(crc);

            Map<String, Object> result = new HashMap<>();
            result.put("input", decimalData);
            result.put("hex", hexData);
            result.put("crc", crc);
            result.put("hexCrc", hexCrc);
            result.put("bytes", bytes.length);

            return ApiResult.success(result);
        } catch (Exception e) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Error processing decimal number: " + e.getMessage()));
        }
    }

    @Operation(summary = "Calculate CRC-16/MODBUS for hex number", description = "Directly calculate CRC-16/MODBUS checksum for hex number input")
    @PostMapping("/calculate-hex-number")
    public ApiResult<Map<String, Object>> calculateCRC16FromHexNumber(@RequestBody Map<String, String> request) {
        String hexNumber = request.get("hexNumber");
        if (hexNumber == null || hexNumber.isEmpty()) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Hex number is required"));
        }

        try {
            // Remove any "0x" prefix if present
            if (hexNumber.toLowerCase().startsWith("0x")) {
                hexNumber = hexNumber.substring(2);
            }
            
            // Ensure even number of characters by padding with leading zero if needed
            if (hexNumber.length() % 2 != 0) {
                hexNumber = "0" + hexNumber;
            }
            
            // Pad hex number to 4 characters (2 bytes) with leading zeros if needed
            while (hexNumber.length() < 4) {
                hexNumber = "00" + hexNumber;
            }
            
            // Create the full data string with prefix
            String allNumber = "00 06 01 34 " + hexNumber;
            
            // Remove spaces and convert to byte array
            String hexData = allNumber.replace(" ", "");
            byte[] bytes = hexStringToByteArray(hexData);
            int crc = CRC16Util.calculateCRC16(bytes);
            String hexCrc = CRC16Util.toHexString(crc);

            Map<String, Object> result = new HashMap<>();
            result.put("input", request.get("hexNumber")); // Keep original input format
            result.put("hex", hexNumber); // Normalized hex format
            result.put("fullData", allNumber); // Full data string
            result.put("crc", crc);
            result.put("hexCrc", hexCrc);
            result.put("bytes", bytes.length);

            return ApiResult.success(result);
        } catch (Exception e) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Error processing hex number: " + e.getMessage()));
        }
    }

    @Operation(summary = "Calculate CRC-16/MODBUS for decimal with fixed prefix", description = "Calculate CRC-16/MODBUS for data with fixed prefix 00 06 01 34 and decimal converted to hex")
    @PostMapping("/calculate-with-prefix")
    public ApiResult<Map<String, Object>> calculateCRC16WithFixedPrefix(@RequestBody Map<String, Long> request) {
        Long decimalData = request.get("decimal");
        if (decimalData == null) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Decimal data is required"));
        }

        try {
            // Convert decimal to hex string
            String hexData = Long.toHexString(decimalData).toUpperCase();
            
            // Ensure even number of characters by padding with leading zero if needed
            if (hexData.length() % 2 != 0) {
                hexData = "0" + hexData;
            }
            
            // Pad to 4 characters (2 bytes) with leading zeros if needed
            while (hexData.length() < 4) {
                hexData = "00" + hexData;
            }
            
            // Create the full data string with fixed prefix
            String allNumber = "00 06 01 34 " + hexData;
            
            // Remove spaces and convert to byte array
            String fullHexData = allNumber.replace(" ", "");
            byte[] bytes = hexStringToByteArray(fullHexData);
            int crc = CRC16Util.calculateCRC16(bytes);
            String hexCrc = CRC16Util.toHexString(crc);

            Map<String, Object> result = new HashMap<>();
            result.put("input", decimalData);
            result.put("hexData", hexData);
            result.put("fullData", allNumber);
            result.put("fullHex", fullHexData);
            result.put("crc", crc);
            result.put("hexCrc", hexCrc);
            result.put("bytes", bytes.length);

            return ApiResult.success(result);
        } catch (Exception e) {
            return ApiResult.error(CommonResponseEnum.INVALID.message("Error processing decimal with fixed prefix: " + e.getMessage()));
        }
    }

    /**
     * Convert hex string to byte array
     *
     * @param hexString hex string
     * @return byte array
     */
    private static byte[] hexStringToByteArray(String hexString) {
        // Ensure even number of characters
        if (hexString.length() % 2 != 0) {
            throw new IllegalArgumentException("Hex string must have an even number of characters");
        }
        
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i+1), 16));
        }
        return data;
    }
}